package com.cn.sl.server.api.system.role.service.impl

import com.cn.sl.server.api.system.menu.dao.rdb.MenuDao
import com.cn.sl.server.api.system.role.dao.RoleDao
import com.cn.sl.server.api.system.role.model.dto.AddRoleDto
import com.cn.sl.server.api.system.role.model.dto.EditRoleDto
import com.cn.sl.server.api.system.role.model.dto.RoleDto
import com.cn.sl.server.api.system.role.model.dto.RoleListQueryDto
import com.cn.sl.server.api.system.role.model.entity.QRoleEntity
import com.cn.sl.server.api.system.role.model.entity.RoleEntity
import com.cn.sl.server.api.system.role.service.RoleService
import com.cn.sl.server.common.annotation.transaction.Commit
import com.cn.sl.server.common.annotation.transaction.ReadOnly
import com.cn.sl.server.common.dao.BaseDao
import com.cn.sl.server.common.dto.PageDto
import com.querydsl.core.BooleanBuilder
import org.springframework.data.domain.Page
import org.springframework.data.domain.Sort
import org.springframework.stereotype.Service

@Service
class RoleServiceImpl(
    val roleDao: RoleDao,
    val menuDao: MenuDao
) : RoleService {

    @ReadOnly
    override fun findAll(dto: RoleListQueryDto): List<RoleDto> {
        return roleDao.findAll(
            query(dto),
            Sort.by(Sort.Order.desc(entity.id.metadata.name))
        )
            .map { RoleDto(it) }
    }

    @ReadOnly
    override fun find(dto: RoleListQueryDto): PageDto<RoleDto> {
        val page: Page<RoleEntity> = roleDao.findAll {
            val booleanBuilder = query(dto)

            BaseDao.PageQueryAct(
                booleanBuilder,
                dto.page,
                dto.pageSize,
                Sort.by(Sort.Direction.DESC, entity.id.metadata.name)
            )
        }
        return PageDto(
            dto.page,
            dto.pageSize,
            page.totalElements.toInt(),
            page.totalPages,
            page.content.map { RoleDto(it) }
        )
    }

    @Commit
    override fun add(dto: AddRoleDto) {
        roleDao.save(dto.toEntity() {
            menuDao.findAllById(it)
        })
    }

    @Commit
    override fun edit(dto: EditRoleDto) {
        roleDao.findById(dto.id).let {
            dto.merge(it) {
                menuDao.findAllById(it)
            }
        }
    }

    @ReadOnly
    override fun findById(id: Long): RoleDto {
        return RoleDto(roleDao.findById(id))
    }

    @ReadOnly
    override fun delete(id: Long) {
        roleDao.deleteById(id)
    }

    private fun query(dto: RoleListQueryDto): BooleanBuilder {
        return BooleanBuilder().apply {
            if (dto.name != null) {
                and(entity.name.contains(dto.name))
            }
            if (dto.memo != null) {
                and(entity.memo.contains(dto.memo))
            }
        }
    }

    companion object {
        val entity: QRoleEntity = QRoleEntity.roleEntity
    }
}